package com.project.filetsystem.controller;


import com.project.filetsystem.service.IVideoService;
import com.project.filetsystem.vo.FileVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import sun.awt.image.OffScreenImage;

import javax.imageio.ImageIO;
import javax.imageio.stream.FileCacheImageOutputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.*;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;

import java.util.List;


/**
 * @author zhujiaqaing
 * @date 2022/10/22 11:52
 */
@RestController
@RequestMapping("file")
@ResponseBody
@Slf4j
public class FileController {

    @Value("${file.url}")
    private String fileUrl;
    @Autowired
    IVideoService videoService;

    /**
     * 返回视频文件vo对象集合
     * @return
     */
    @GetMapping("/folder/list")
    public  List<FileVo> getFiles(String filePath) throws Exception {
        List<FileVo> fileList = new ArrayList<>();
        if(null == filePath){
            File[] roots = File.listRoots();
            for(File file : roots){
                if(file.isDirectory()){
                    FileVo fileVo = new FileVo();
                    fileVo.setName(file.getCanonicalPath());
                    fileVo.setAbsolutePath(Base64Utils.encodeToString(file.getAbsolutePath().getBytes()));
                    fileVo.setType("folder");
                    fileList.add(fileVo);
                }
            }
            return fileList;
        }else {
            byte[] filePath1 = Base64Utils.decodeFromString(filePath);
            filePath = new String(filePath1);
            System.out.println(filePath);
        }
        File folderFile = null;
        log.info("filePath:{}",filePath);
        folderFile  =  new File(filePath);
        log.info(filePath);
        //判断保存的文件的文件夹是否存在，不存在创建。
        File[] list = folderFile.listFiles();
        for (File file : list) {
            if (null != file && file.exists() && file.isFile()) {
                if (file.getName().indexOf(".mp4") > 0 ||
                        file.getName().indexOf(".m4v") > 0 ||
                        file.getName().indexOf(".ts") > 0 ||
                        file.getName().indexOf(".rm") > 0 ||
                        file.getName().indexOf(".rmvb") > 0 ||
                        file.getName().indexOf(".asf") > 0 ||
                        file.getName().indexOf(".flv") > 0 ||
                        file.getName().indexOf(".mov") > 0 ||
                        file.getName().indexOf(".qt") > 0 ||
                        file.getName().indexOf(".wmv") > 0 ||
                        file.getName().indexOf(".mpeg") > 0 ||
                        file.getName().indexOf(".mkv") > 0 ||
                        file.getName().indexOf(".avi") > 0
                ) {
                    FileVo vo = new FileVo();
                    vo.setName(file.getAbsolutePath().replace(fileUrl,"").replace("\\","_"));
                    vo.setAbsolutePath(Base64Utils.encodeToString(file.getAbsolutePath().getBytes(StandardCharsets.UTF_8)));
                    vo.setType("video");
                    //浏览图片地址设置
                    String imageurl = videoService.getImageNameByFolderName(folderFile.getAbsolutePath(), file.getName());
                    vo.setImageUrl(imageurl);
                    fileList.add(vo);
                }
            }else if(null != file && file.exists() && file.isDirectory()){
                FileVo vo = new FileVo();
                vo.setName(file.getAbsolutePath().replace(fileUrl,"").replace("\\","_"));
                vo.setAbsolutePath(Base64Utils.encodeToString(file.getAbsolutePath().getBytes(StandardCharsets.UTF_8)));
                vo.setType("folder");
                fileList.add(vo);
            }else  {
                FileVo vo = new FileVo();
                vo.setType("file");
                vo.setName(file.getAbsolutePath().replace(fileUrl,"").replace("\\","_"));
                vo.setAbsolutePath(Base64Utils.encodeToString(file.getAbsolutePath().getBytes(StandardCharsets.UTF_8)));
            }
        }
        return fileList;
    }

    /**
     * 视频播放接口
     * @param fileName
     * @param request
     * @param response
     * @throws IOException
     */
    @GetMapping("/play")
    public void play(HttpServletRequest request, HttpServletResponse response,String fileName) throws IOException {
        byte[] filePath1 = Base64Utils.decodeFromString(fileName);
        fileName = new String(filePath1);
        RandomAccessFile targetFile = null ;
        OutputStream outputStream = null;
        try {
            String imagestr = fileName;

            outputStream = response.getOutputStream();
            response.reset();;
            //获取请求头智能的range值
            String rangeString = request.getHeader(HttpHeaders.RANGE);
            System.out.println("rangeString: " + rangeString);
            //打开文件
            String path =  imagestr;
            log.info(path);
            File file = new File(path);
            if(file.exists()){
                //使用RandomAccessFile读取文件
                targetFile = new RandomAccessFile(file,"r");
                long fileLength = targetFile.length();
                long requestSize = (int)fileLength;
                //分段下载视频
                if(StringUtils.hasText(rangeString)){
                    //从Range中提取需要获取数据的开始和结束位置
                    long requestStart = 0 , requestEnd = 0 ;
                    String[] ranges = rangeString.split("=");
                    if (ranges.length > 1) {
                        String[] rangeDatas = ranges[1].split("-");
                        requestStart = Integer.parseInt(rangeDatas[0]);
                        if (rangeDatas.length > 1) {
                            requestEnd = Integer.parseInt(rangeDatas[1]);
                        }
                    }
                    if (requestEnd != 0 && requestEnd > requestStart) {
                        requestSize = requestEnd - requestStart + 1;
                    }
                    //根据协议设置请求头
                    response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
                    response.setHeader(HttpHeaders.CONTENT_TYPE, "video/mp4");
                    if (!StringUtils.hasText(rangeString)) {
                        response.setHeader(HttpHeaders.CONTENT_LENGTH, fileLength + "");
                    } else {
                        long length;
                        if (requestEnd > 0) {
                            length = requestEnd - requestStart + 1;
                            response.setHeader(HttpHeaders.CONTENT_LENGTH, "" + length);
                            response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + requestStart + "-" + requestEnd + "/" + fileLength);
                        } else {
                            length = fileLength - requestStart;
                            response.setHeader(HttpHeaders.CONTENT_LENGTH, "" + length);
                            response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + requestStart + "-" + (fileLength - 1) + "/"
                                    + fileLength);
                        }
                    }
                    //断点传输下载视频返回206
                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                    //设置targetFile，从自定义位置开始读取数据
                    targetFile.seek(requestStart);
                } else {
                    //如果Range为空则下载整个视频
                    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=test.mp4");
                    //设置文件长度
                    response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileLength));
                }

                //从磁盘读取数据流返回
                byte[] cache = new byte[1024];
                try {
                    while (requestSize > 0) {
                        int len = targetFile.read(cache);
                        if (requestSize < cache.length) {
                            outputStream.write(cache, 0, (int) requestSize);
                        } else {
                            outputStream.write(cache, 0, len);
                            if (len < cache.length) {
                                break;
                            }
                        }
                        requestSize -= cache.length;
                    }
                } catch (IOException e) {
                    // tomcat原话。写操作IO异常几乎总是由于客户端主动关闭连接导致，所以直接吃掉异常打日志
                    //比如使用video播放视频时经常会发送Range为0- 的范围只是为了获取视频大小，之后就中断连接了
                    log.info(e.getMessage());
                }
            } else {
                throw new RuntimeException("文件路劲有误");
            }
            outputStream.flush();
        } catch (Exception e) {
            log.error("文件传输错误", e);
        }finally {
            if(outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error("流释放错误", e);
                }
            }
            if(targetFile != null){
                try {
                    targetFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    log.error("文件流释放错误", e);
                }
            }
        }
    }



    public void image(String fileName , HttpServletRequest request, HttpServletResponse response){
        ServletOutputStream out = null;
        FileInputStream ips = null;
        try {
            String imagestr = "";
            String[] strs = fileName.split("_");
            if(null != strs ){
                for(int i = 0 ; i < strs.length;i++){
                    imagestr += strs[i] +"\\";
                }
            }
            imagestr = imagestr.substring(0,imagestr.lastIndexOf("\\"));
            imagestr = fileUrl + imagestr;
            log.info("imagestr:{}",imagestr);
            //获取文件存放的路径
            File file = new File(imagestr);
            String fileNamestr =file.getName();
            //获取到文字 数据库里对应的附件名字加上老的文件名字：filename 截取到后面的文件类型 例：txt  组成一个新的文件名字：newFileName
            if(!file.exists()) {
                //如果文件不存在就跳出
                return;
            }
            ips = new FileInputStream(file);
            response.setContentType("image/png");
            //为文件重新设置名字，采用数据库内存储的文件名称
            response.addHeader("Content-Disposition", "attachment; filename=\"" + new String(fileNamestr.getBytes("UTF-8"),"ISO8859-1") + "\"");
            out = response.getOutputStream();
            //读取文件流
            int len = 0;
            byte[] buffer = new byte[1024 * 10];
            while ((len = ips.read(buffer)) != -1){
                out.write(buffer,0,len);
            }
            out.flush();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if(null != out){
                    out.close();
                }
                if(null != out){
                    ips.close();

                }
            } catch (IOException e) {
                System.out.println("关闭流出现异常");
                e.printStackTrace();
            }
        }
    }

    @GetMapping("/image")
    public void getImage(String fileName,HttpServletResponse response) throws IOException {
        fileName = new String(Base64Utils.decodeFromString(fileName));
        ImageIcon icon = (ImageIcon) FileSystemView.getFileSystemView().getSystemIcon(new File(fileName));
        java.awt.Image image = icon.getImage();
        OutputStream outputStream = response.getOutputStream();
        ImageObserver imageObserver = new ImageObserver() {
            @Override
            public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
                return true;
            }
        };
        BufferedImage bufferedImage = new BufferedImage(icon.getIconWidth(),icon.getIconHeight(),BufferedImage.TYPE_INT_RGB);
        bufferedImage.getGraphics().drawImage(image,icon.getIconWidth(),icon.getIconHeight(),imageObserver);
        ImageIO.write(bufferedImage,"ico",outputStream);
        outputStream.flush();

    }

}
